home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format CD 24 / Amiga Format AFCD24 (Feb 1998, Issue 108).iso / -seriously_amiga- / shareware / programming / c / vbcc / pasm / output_ehf.c < prev    next >
C/C++ Source or Header  |  1998-01-05  |  10KB  |  375 lines

  1. /* $VER: pasm output_ehf.c V0.4 (02.07.97)
  2.  *
  3.  * This file is part of pasm, a portable PowerPC assembler.
  4.  * Copyright (c) 1997  Frank Wille
  5.  *
  6.  * pasm is freeware and part of the portable and retargetable ANSI C
  7.  * compiler vbcc, copyright (c) 1995-97 by Volker Barthelmann.
  8.  * pasm may be freely redistributed as long as no modifications are
  9.  * made and nothing is charged for it. Non-commercial usage is allowed
  10.  * without any restrictions.
  11.  * EVERY PRODUCT OR PROGRAM DERIVED DIRECTLY FROM MY SOURCE MAY NOT BE
  12.  * SOLD COMMERCIALLY WITHOUT PERMISSION FROM THE AUTHOR.
  13.  *
  14.  *
  15.  * v0.4 (02.07.97) phx
  16.  *      File created.
  17.  */
  18.  
  19.  
  20. #define OUTPUT_EHF_C
  21. #include "ppcasm.h"
  22. #include "ehf.h"
  23.  
  24.  
  25. struct XRefNode {
  26.   struct node n;
  27.   char *sym_name;
  28.   uint8 ref_type;
  29.   int noffsets;
  30.   struct list xreflist;
  31. };
  32.  
  33.  
  34. static char *output_name;
  35. static int nsecs = 0;
  36. static bool exthunk = FALSE;
  37.  
  38.  
  39. void output_ehf(struct GlobalVars *);
  40.  
  41. static void reloc_hunk(FILE *,struct Section *,uint8,uint32);
  42. static void unsupp_relocs(struct Section *);
  43. static void ext_header(FILE *);
  44. static void ext_refs(FILE *,struct GlobalVars *,struct Section *);
  45. static void ext_defs(FILE *,struct GlobalVars *,uint32,uint8,uint32);
  46. static uint32 word_strlen(char *);
  47. static void write_name(FILE *,struct GlobalVars *,char *);
  48. static void fwalign(FILE *,struct GlobalVars *,uint32);
  49. static void fw(FILE *,void *,size_t);
  50. static void fw4(FILE *,uint32);
  51.  
  52.  
  53.  
  54. void output_ehf(struct GlobalVars *gv)
  55. {
  56.   struct Section *nextsec,*sec=(struct Section *)gv->sectionlist.first;
  57.   struct Symbol *symchain;
  58.   uint32 index;
  59.   FILE *fp;
  60.  
  61.   /* assign an index to each valid section */
  62.   while (nextsec = (struct Section *)sec->n.next) {
  63.     if (!(sec->flags & SF_DISCARD) && sec->size > 0)
  64.       sec->index = nsecs++;
  65.     sec = nextsec;
  66.   }
  67.  
  68.   /* create output file */
  69.   output_name = gv->dest_name;
  70.  
  71.   if (fp = fopen(output_name,"w")) {  /* create output file */
  72.     fw4(fp,HUNK_UNIT);
  73.     if (gv->ident) {
  74.       fw4(fp,word_strlen(gv->ident));  /* unit name */
  75.       write_name(fp,gv,gv->ident);
  76.     }
  77.     else
  78.       fw4(fp,0);
  79.  
  80.  
  81.     /* section loop */
  82.     sec = (struct Section *)gv->sectionlist.first;
  83.     while (nextsec = (struct Section *)sec->n.next) {
  84.       if (!(sec->flags & SF_DISCARD) && sec->size > 0) {
  85.         index = sec->index;
  86.  
  87.         /* section name */
  88.         fw4(fp,HUNK_NAME);
  89.         fw4(fp,word_strlen(sec->name));
  90.         write_name(fp,gv,sec->name);
  91.  
  92.         /* section type and size */
  93.         switch(sec->type) {
  94.           case ST_CODE:
  95.             fw4(fp,HUNK_PPC_CODE);
  96.             break;
  97.           case ST_DATA:
  98.             fw4(fp,HUNK_DATA);
  99.             break;
  100.           case ST_UDATA:
  101.             fw4(fp,HUNK_BSS);
  102.             break;
  103.           default:  /* section type not supported in EHF */
  104.             error(52,sec->name,(int)sec->type);
  105.             fw4(fp,HUNK_DATA);  /* defaults to HUNK_DATA */
  106.             break;
  107.         }
  108.         fw4(fp,(uint32)(sec->size+3)>>2);
  109.  
  110.         /* write section contents */
  111.         if (!(sec->flags & SF_UNINITIALIZED)) {
  112.           fw(fp,sec->contents,(uint32)sec->size);
  113.           fwalign(fp,gv,(uint32)sec->size);
  114.         }
  115.  
  116.         /* relocation hunks */
  117.         reloc_hunk(fp,sec,R_PPC_ADDR32,HUNK_ABSRELOC32);
  118. /* @@@  reloc_hunk(fp,sec,R_PPC_ADDR16,HUNK_ABSRELOC16); */
  119.         reloc_hunk(fp,sec,R_PPC_REL24,HUNK_RELRELOC26);
  120.         reloc_hunk(fp,sec,R_PPC_REL14,HUNK_RELRELOC16);
  121.         reloc_hunk(fp,sec,R_PPC_REL14_BRTAKEN,HUNK_RELRELOC16);
  122.         reloc_hunk(fp,sec,R_PPC_REL14_BRNTAKEN,HUNK_RELRELOC16);
  123.         reloc_hunk(fp,sec,R_PPC_REL32,HUNK_RELRELOC32);
  124.         reloc_hunk(fp,sec,R_PPC_TOC16,HUNK_DREL16);
  125.         unsupp_relocs(sec);  /* print unsupported relocations */
  126.  
  127.         /* external references and global definitions */
  128.         ext_refs(fp,gv,sec);
  129.         ext_defs(fp,gv,index,SYM_RELOC,EXT_DEF);
  130.         if (index == 0)  /* put absolute definitions in first HUNK_EXT */
  131.           ext_defs(fp,gv,0xffff,SYM_ABS,EXT_ABS);
  132.         if (exthunk)
  133.           fw4(fp,0);  /* close HUNK_EXT block */
  134.  
  135.         /* symbol table */
  136.         ext_defs(fp,gv,index,SYM_RELOC,EXT_SYMB);
  137.  
  138.         fw4(fp,HUNK_END);  /* end of this hunk */
  139.       }
  140.       sec = nextsec;
  141.     }
  142.  
  143.     fclose(fp);
  144.   }
  145.   else
  146.     error(25,output_name);  /* unable to create output file */
  147. }
  148.  
  149.  
  150. static void reloc_hunk(FILE *fp,struct Section *sec,uint8 r,uint32 ehfrel)
  151. /* generate an EHF relocation hunk for a specific reloc type */
  152. {
  153.   struct Reloc *nextrel,*rel=(struct Reloc *)sec->reloclist.first;
  154.   struct list **rlist=alloc(nsecs*sizeof(struct list *));
  155.   int *rcnt=alloczero(nsecs*sizeof(int));  /* reloc cnt for all sections */
  156.   bool hunk_required=FALSE;
  157.   int i;
  158.  
  159.   for (i=0; i<nsecs; i++) {  /* empty reloc lists for each section */
  160.     rlist[i] = alloc(sizeof(struct list));
  161.     initlist(rlist[i]);
  162.   }
  163.  
  164.   while (nextrel = (struct Reloc *)rel->n.next) {
  165.     if (rel->type == r) {
  166.       /* move reloc node of correct type into relocssect's rlist */
  167.       remnode(&rel->n);
  168.       addtail(rlist[rel->relocsect->index],&rel->n);
  169.       rcnt[rel->relocsect->index]++;
  170.       hunk_required = TRUE;
  171.     }
  172.     rel = nextrel;
  173.   }
  174.  
  175.   if (hunk_required) {  /* there's at least one relocation */
  176.     fw4(fp,ehfrel);  /* reloc hunk id */
  177.     for (i=0; i<nsecs; i++) {
  178.       if (rcnt[i]) {
  179.         fw4(fp,(uint32)rcnt[i]);  /* number of relocations */
  180.         fw4(fp,(uint32)i);  /* section index */
  181.  
  182.         /* store relocation offsets */
  183.         while(rel = (struct Reloc *)remhead(rlist[i])) {
  184.           fw4(fp,(uint32)rel->offset);
  185.           free(rel);
  186.         }
  187.       }
  188.     }
  189.     fw4(fp,0);  /* no more relocation entries */
  190.   }
  191.  
  192.   /* free dynamically allocated rlists and rcnt array */
  193.   for (i=0; i<nsecs; free(rlist[i++]));
  194.   free(rcnt);
  195. }
  196.  
  197.  
  198. static void unsupp_relocs(struct Section *sec)
  199. {
  200.   struct Reloc *nextrel,*rel=(struct Reloc *)sec->reloclist.first;
  201.  
  202.   while (nextrel = (struct Reloc *)rel->n.next) {
  203.     error(53,elfrel_name[rel->type & ELFRELNAMMSK],rel->offset,sec->name);
  204.     rel = nextrel;
  205.   }
  206. }
  207.  
  208.  
  209. static void ext_header(FILE *fp)
  210. {
  211.   if (!exthunk) {
  212.     exthunk = TRUE;
  213.     fw4(fp,HUNK_EXT);
  214.   }
  215. }
  216.  
  217.  
  218. static void ext_refs(FILE *fp,struct GlobalVars *gv,struct Section *sec)
  219. {
  220.   struct list xnodelist;  /* xrefs with same ref. type and symbol name */
  221.   struct XRefNode *xn,*nextxn;
  222.   struct XReference *xref;
  223.  
  224.   initlist(&xnodelist);
  225.   while (xref = (struct XReference *)remhead(&sec->xreflist)) {
  226.     char *name = xref->xsymbol->name;  /* name of xref'ed symbol */
  227.     uint8 rtype = xref->type;
  228.  
  229.     /* ELF32 -> EHF reference type mapping */
  230.     switch (rtype) {
  231.       case R_PPC_ADDR32:
  232.         rtype = EXT_ABSREF32;
  233.         break;
  234.       case R_PPC_REL24:
  235.         rtype = EXT_RELREF26;
  236.         break;
  237.       case R_PPC_REL14:
  238.       case R_PPC_REL14_BRTAKEN:
  239.       case R_PPC_REL14_BRNTAKEN:
  240.       case R_PPC_ADDR16:
  241.         rtype = EXT_RELREF16;
  242.         break;
  243.       case R_PPC_TOC16:
  244.         rtype = EXT_DEXT16;  /* small data */
  245.         break;
  246.       default:
  247.         error(53,elfrel_name[rtype & ELFRELNAMMSK],xref->offset,sec->name);
  248.         rtype = EXT_RELREF8;  /* @@@ to keep the loop running */
  249.         break;
  250.     }
  251.  
  252.     /* search appropriate XRefNode for referenced symbol and type */
  253.     xn = (struct XRefNode *)xnodelist.first;
  254.     while (nextxn = (struct XRefNode *)xn->n.next) {
  255.       if (!strcmp(name,xn->sym_name) && rtype==xn->ref_type)
  256.         break;
  257.       xn = nextxn;
  258.     }
  259.  
  260.     if (nextxn==NULL) {  /* we have to create a new XRefNode? */
  261.       xn = alloc(sizeof(struct XRefNode));
  262.       xn->sym_name = name;
  263.       xn->ref_type = rtype;
  264.       xn->noffsets = 0;
  265.       initlist(&xn->xreflist);
  266.       addtail(&xnodelist,&xn->n);
  267.     }
  268.  
  269.     /* add new offset to xreflist for same ref. type and symbol name */
  270.     addtail(&xn->xreflist,&xref->n);
  271.     xn->noffsets++;
  272.   }
  273.  
  274.   if (xnodelist.first->next) {  /* at least one reference in this section? */
  275.     ext_header(fp);
  276.     while (xn = (struct XRefNode *)remhead(&xnodelist)) {
  277.       fw4(fp,((uint32)xn->ref_type << 24) | word_strlen(xn->sym_name));
  278.       write_name(fp,gv,xn->sym_name);  /* symbol's name */
  279.       fw4(fp,(uint32)xn->noffsets);  /* number of references */
  280.       while (xref = (struct XReference *)remhead(&xn->xreflist)) {
  281.         fw4(fp,(uint32)xref->offset);  /* offset */
  282.         free(xref);
  283.       }
  284.       free(xn);
  285.     }
  286.   }
  287. }
  288.  
  289.  
  290. static void ext_defs(FILE *fp,struct GlobalVars *gv,uint32 idx,
  291.                      uint8 stype,uint32 xdeftype)
  292. {
  293.   struct Symbol *sym;
  294.   bool xdefs = FALSE;
  295.   int i;
  296.  
  297.   for (i=0; i<SYMHTABSIZE; i++) {
  298.     sym = gv->symbols[i];
  299.     while (sym) {
  300.       if (sym->type==stype &&
  301.           (sym->info==SYMI_NOTYPE || sym->info==SYMI_FUNC)) {
  302.         if (idx == ((stype==SYM_RELOC) ? sym->relsect->index : 0xffff)) {
  303.           if (sym->bind > SYMB_LOCAL) {
  304.             if (!xdefs) {
  305.               xdefs = TRUE;
  306.               if (xdeftype == EXT_SYMB)
  307.                 fw4(fp,HUNK_SYMBOL);
  308.               else
  309.                 ext_header(fp);
  310.             }
  311.  
  312.             /* generate xdef oder symbol table entry */
  313.             fw4(fp,(xdeftype << 24) | word_strlen(sym->name));
  314.             write_name(fp,gv,sym->name);  /* symbol's name */
  315.             fw4(fp,sym->value);  /* ... and its value */
  316.           }
  317.         }
  318.       }
  319.       sym = sym->hash_chain;
  320.     }
  321.   }
  322.   if (xdefs && xdeftype==EXT_SYMB)
  323.     fw4(fp,0);  /* end of symbol table for this hunk */
  324. }
  325.  
  326.  
  327. static uint32 word_strlen(char *s)
  328. /* calculate number of 32 bit words required for
  329.    a string without terminator */
  330. {
  331.   uint32 l;
  332.  
  333.   if (l = (uint32)strlen(s))
  334.     l = (l+3)>>2;
  335.   return (l);
  336. }
  337.  
  338.  
  339. static void write_name(FILE *fp,struct GlobalVars *gv,char *name)
  340. /* write a unit/section/symbol name word-aligned */
  341. {
  342.   size_t nl=strlen(name);
  343.  
  344.   fw(fp,name,nl);
  345.   fwalign(fp,gv,(uint32)nl);
  346. }
  347.  
  348.  
  349. static void fwalign(FILE *fp,struct GlobalVars *gv,uint32 n)
  350. {
  351.   fw(fp,gv->alignment_bytes,(4-(n&3))&3);
  352. }
  353.  
  354.  
  355. static void fw(FILE *fp,void *buf,size_t len)
  356. {
  357.   if (len) {
  358.     if (!fwrite(buf,1,len,fp)) {
  359.       fclose(fp);
  360.       error(26,output_name);  /* write error */
  361.     }
  362.   }
  363. }
  364.  
  365.  
  366. static void fw4(FILE *fp,uint32 w)
  367. /* write a 32 bit word, automatic endian conversion */
  368. {
  369.   w = ECVW(w);
  370.   if (!fwrite(&w,1,sizeof(uint32),fp)) {
  371.     fclose(fp);
  372.     error(26,output_name);  /* write error */
  373.   }
  374. }
  375.